#include "shared_object.h"
#include <stdio.h>
#include <pthread.h>
using namespace std;

SharedObject::SharedObject(){
	pthread_mutex_init(&mutex_cpu_result, NULL);
	pthread_mutex_init(&mutex_gpu_result, NULL);

	pthread_cond_init(&cpu_result_ready, NULL);
	pthread_cond_init(&gpu_result_ready, NULL);

	cpu_ready_indicator = false;
	gpu_ready_indicator = false;
}

// this method access by CPU
void SharedObject::set_cpu_result(vector<T>& input){
	pthread_mutex_lock( &mutex_cpu_result );

	cpu_ready_indicator = true;
	pthread_cond_signal(&cpu_result_ready);
	cpu2gpu = input;

	pthread_mutex_unlock(&mutex_cpu_result);
}

// this method called by GPU
void SharedObject::get_cpu_result(thrust::host_vector<T>& result){

	pthread_mutex_lock(&mutex_cpu_result);

	while(!cpu_ready_indicator){
		pthread_cond_wait(&cpu_result_ready, &mutex_cpu_result);
	}
	result = cpu2gpu;
	cpu_ready_indicator = false;

	pthread_mutex_unlock(&mutex_cpu_result);
}

void SharedObject::set_gpu_result(thrust::device_vector<T>& result){

	pthread_mutex_lock(&mutex_gpu_result);

	gpu_ready_indicator = true;
	pthread_cond_signal(&gpu_result_ready);
	gpu2cpu.resize(result.size());
	cudaMemcpy(&gpu2cpu[0],thrust::raw_pointer_cast(result.data()),result.size()*sizeof(T),cudaMemcpyDeviceToHost);
	
	pthread_mutex_unlock(&mutex_gpu_result);
}

void SharedObject::get_gpu_result(vector<T>& result){

	pthread_mutex_lock(&mutex_gpu_result);

	while(!gpu_ready_indicator){
		pthread_cond_wait(&gpu_result_ready, &mutex_gpu_result);
	}
	result = gpu2cpu;
	gpu_ready_indicator = false;

	pthread_mutex_unlock(&mutex_gpu_result);
}